package protocol

import (
	"GameServer/Protocol/protocol"
	"net"
	"runtime"
	"runtime/debug"
	"sync"
	"sync/atomic"

	log "github.com/sirupsen/logrus"
)

type Server interface {
	Start()
	Stop()
	ClientCallBack() ClientCallBack
	AddClient(clientId int64, c *Client)
	RemoveClient(clientId int64)
	Protocol() protocol.Protocol
	ClientIDSequence() int64
	WaitGroupFunc(f func())
}

type TcpServer struct {
	ln               net.Listener
	wg               *sync.WaitGroup
	exitChan         chan struct{}
	clientCallBack   func() ClientCallBack
	protocol         protocol.Protocol
	clientIDSequence int64
	clientLock       sync.RWMutex
	clients          map[int64]*Client
}

func NewTcpServer(ln net.Listener, f func() ClientCallBack, protocol protocol.Protocol) *TcpServer {
	s := &TcpServer{
		ln:             ln,
		wg:             new(sync.WaitGroup),
		exitChan:       make(chan struct{}),
		clientCallBack: f,
		protocol:       protocol,
		clients:        make(map[int64]*Client),
	}
	return s
}

func (s *TcpServer) Start() {
	s.wg.Add(1)
	defer func() {
		s.ln.Close()
		s.wg.Done()
	}()
	for {
		clientConn, err := s.ln.Accept()
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
				runtime.Gosched()
				continue
			}
			return
		}
		// clientConn.(*net.TCPConn).SetReadBuffer(bytes int)
		clientConn.(*net.TCPConn).SetWriteBuffer(1024 * 16)
		// 建立新的socket连接，打印
		log.WithFields(log.Fields{
			"ip": clientConn.RemoteAddr().String(),
		}).Info("client conn")
		s.WaitGroupFunc(func() {
			newClient(s, clientConn).Do()
		})
		// s.wg.Add(1)
		// go func() {
		// 	defer s.wg.Done()
		// 	newClient(s, clientConn).Do()
		// }()
	}
}

func (s *TcpServer) Stop() {
	s.ln.Close()
	close(s.exitChan)
	for _, c := range s.clients {
		c.Close()
	}
	s.wg.Wait()
}

func (s *TcpServer) WaitGroupFunc(f func()) {
	s.wg.Add(1)
	go func() {
		defer func() {
			s.wg.Done()
			if err := recover(); err != nil {
				log.WithFields(log.Fields{
					"data": string(debug.Stack()),
				}).Error("tcp server WaitGroupFunc err:", err)
			}
		}()
		f()
	}()
}

func (s *TcpServer) AddClient(clientId int64, c *Client) {
	s.clientLock.Lock()
	s.clients[clientId] = c
	s.clientLock.Unlock()
}

func (s *TcpServer) RemoveClient(clientId int64) {
	s.clientLock.Lock()
	defer s.clientLock.Unlock()
	if _, ok := s.clients[clientId]; !ok {
		return
	}
	delete(s.clients, clientId)
}

func (s *TcpServer) Protocol() protocol.Protocol {
	return s.protocol
}

func (s *TcpServer) ClientCallBack() ClientCallBack {
	return s.clientCallBack()
}

func (s *TcpServer) ClientIDSequence() int64 {
	atomic.AddInt64(&s.clientIDSequence, 1)
	return s.clientIDSequence
}
